import { Role as RoleEntity } from '@/entity/Role';
import { RolePermission as RolePermissionEntity } from '@/entity/RolePermission';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Like, Repository } from 'typeorm';
import { CommonService } from '../common/common.service';
import { UserRole as UserRoleEntity } from '@/entity/UserRole';
import { PaginationConfig } from '@/types';

@Injectable()
export class RoleService extends CommonService<RoleEntity> {
  constructor(
    @InjectRepository(RoleEntity)
    private readonly roleRepository: Repository<RoleEntity>,
    private dataSource: DataSource,
  ) {
    super(roleRepository);
  }

  // 查找角色和角色权限
  async findRoleWithPermission(roleId: number) {
    return this.roleRepository.findOne({
      where: {
        id: roleId,
      },
      join: {
        alias: 'role',
        leftJoinAndSelect: {
          rolePermission: 'role.rolePermissions',
          permission: 'rolePermission.permission',
        },
      },
    });
  }

  // 更新角色权限
  async updateRoleWithPermission(
    roleId: number,
    toUpdateRole: Pick<RoleEntity, 'name' | 'znName'>,
    paramsPermissionIds: number[],
  ) {
    const roleEntity = await this.findRoleWithPermission(roleId);
    const oldPermissionIds = roleEntity.rolePermissions.map(
      (item) => item.permission.id,
    );
    const oldPermissionIdsMap = oldPermissionIds.reduce(
      (prev, permissionId) => {
        prev[permissionId] = true;
        return prev;
      },
      {} as { [key: number]: boolean },
    );
    const paramsPermissionIdsMap = paramsPermissionIds.reduce(
      (prev, permissionId) => {
        prev[permissionId] = true;
        return prev;
      },
      {} as { [key: number]: boolean },
    );
    // 旧的ids 比 新的ids 多出来的就是删除的
    const toDeletePermissionIds = oldPermissionIds.filter(
      (permissionId) => !paramsPermissionIdsMap[permissionId],
    );
    const toAddPermissionIds = paramsPermissionIds.filter(
      (permissionId) => !oldPermissionIdsMap[permissionId],
    );
    // 开启事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    try {
      // 开启事务
      await queryRunner.startTransaction();
      const allPromise = [];
      //删除多个
      if (toDeletePermissionIds.length) {
        allPromise.push(
          queryRunner.manager
            .getRepository(RolePermissionEntity)
            .createQueryBuilder()
            .delete()
            .where('roleId = :roleId', {
              roleId,
            })
            .andWhere('permissionId IN (:...permissionIds)', {
              permissionIds: toDeletePermissionIds,
            })
            .execute(),
        );
      }
      // 插入多个
      if (toAddPermissionIds.length) {
        allPromise.push(
          queryRunner.manager
            .getRepository(RolePermissionEntity)
            .createQueryBuilder()
            .insert()
            .values(
              toAddPermissionIds.map((permissionId) => ({
                roleId,
                permissionId,
              })),
            )
            .execute(),
        );
      }
      // 修改当前的角色 name、znName
      if (Object.keys(toUpdateRole).length) {
        allPromise.push(
          queryRunner.manager.query(
            `UPDATE role SET name = '${toUpdateRole.name}', zn_name = '${toUpdateRole.znName}' WHERE id = ${roleId}`,
          ),
        );
      }
      // 等待所有任务完成
      await Promise.all(allPromise);
      // 结束事务
      await queryRunner.commitTransaction();
    } catch (error) {
      // 发生错误回滚
      await queryRunner.rollbackTransaction();
      throw error;
    }
    // 释放
    await queryRunner.release();
  }

  // 创建角色
  async createRole(
    toAddRoleInfo: Pick<RoleEntity, 'name' | 'znName'>,
    permissionIds: number[],
  ) {
    // 开启事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    let resultSetId: number | null = null;
    try {
      // 开启事务
      await queryRunner.startTransaction();
      // 创建角色
      resultSetId = (
        await queryRunner.manager.query(
          `INSERT INTO role (name, zn_name) VALUES ('${toAddRoleInfo.name}', '${toAddRoleInfo.znName}')`,
        )
      ).insertId;
      console.log(resultSetId);
      // 创建角色绑定对应关系
      await queryRunner.manager
        .getRepository(RolePermissionEntity)
        .createQueryBuilder()
        .insert()
        .values(
          permissionIds.map((permissionId) => ({
            permissionId,
            roleId: resultSetId,
          })),
        )
        .execute();
      // 结束事务
      await queryRunner.commitTransaction();
    } catch (error) {
      // 发生错误回滚
      await queryRunner.rollbackTransaction();
      throw error;
    }
    // 释放
    await queryRunner.release();
    return resultSetId;
  }

  // 删除角色
  async deleteRoleById(roleId: number) {
    // 开启事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    try {
      // 开启事务
      await queryRunner.startTransaction();
      // 删除关联角色的角色权限记录
      await queryRunner.manager
        .getRepository(RolePermissionEntity)
        .createQueryBuilder()
        .delete()
        .where('roleId = :roleId', { roleId })
        .execute();
      // 删除关联角色的用户角色记录
      await queryRunner.manager
        .getRepository(UserRoleEntity)
        .createQueryBuilder()
        .delete()
        .where('roleId = :roleId', { roleId })
        .execute();
      // 最后删除角色资源
      await queryRunner.manager.query(`
        DELETE FROM role WHERE id = ${roleId}
      `);
      // 结束事务
      await queryRunner.commitTransaction();
    } catch (error) {
      // 发生错误回滚
      await queryRunner.rollbackTransaction();
      throw error;
    }
    // 释放
    await queryRunner.release();
  }

  async findAllAndCount(
    findOption: Partial<RoleEntity>,
    pagination: PaginationConfig,
  ) {
    const [list, total] = await this.roleRepository.findAndCount({
      where: {
        // 字符串不为空
        name: findOption.name ? Like(`%${findOption.name}%`) : undefined,
        znName: findOption.znName ? Like(`%${findOption.znName}%`) : undefined,
        // id 肯定为正整数
        id: findOption.id ? findOption.id : undefined,
      },
      skip: pagination.pageSize * (pagination.current - 1),
      take: pagination.pageSize,
    });
    return {
      list,
      total,
    };
  }
}
